/*****************************************************************************
 *   Copyright 2005 Tim A Wang
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 ****************************************************************************/
package com.jb.web.model;

import com.jb.faces.el.AttributeEvaluator;
import com.jb.framework.util.PropUtil;
import com.jb.search.HitMateData;
import com.jb.search.HitsRenderer;
import com.jb.search.RenderException;
import com.jb.search.SearchHits;
import com.jb.search.SourceDocument;
import com.jb.search.lucene.CatalogSearch;
import com.jb.search.meta.Catalog;
import com.jb.search.meta.CatalogManager;
import com.jb.web.context.WebContext;

import java.beans.PropertyDescriptor;

import java.io.File;
import java.io.StringWriter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.jb.faces.context.FacesContext;

import com.jb.framework.util.BeanUtil;

import com.jb.util.ClassUtil;

import javax.swing.event.ListDataListener;


public class SearchList extends Variable implements JBListModel {
    static final long serialVersionUID = 123123L;

    static {
        publish(SearchList.class, DATA, "pageSize");
        publish(SearchList.class, DATA, "beanClass");
        publish(SearchList.class, DATA, "category");
        publish(SearchList.class, DATA, "value");
    }

    List list = new ArrayList();
    StringBuffer result;
    private String beanClass;
    private String category;
    private int pageNo;
    private int pageSize = 10;
    private int totalPages;

    public void setBeanClass(String beanClass) {
        this.beanClass = beanClass;
    }

    public String getBeanClass() {
        return beanClass;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getCategory() {
        return category;
    }

    public Object getElementAt(int index) {
        return list.get(index);
    }

    public void setList(List list) {
        this.list = list;
    }

    public List getList(WebContext pCtx) {
        populate(pCtx);

        return list;
    }

    public List getList() {
        return list;
    }

    public void setPageNo(int pageNo) {
        this.pageNo = pageNo;
    }

    public int getPageNo() {
        return pageNo;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getPageSize() {
        return pageSize;
    }

    public StringBuffer getResult() {
        return result;
    }

    public int getSize() {
        if (list == null) {
            return 0;
        } else {
            return list.size();
        }
    }

    public void setTotalPages(int totalPages) {
        this.totalPages = totalPages;
    }

    public int getTotalPages() {
        return totalPages;
    }

    public void addListDataListener(ListDataListener l) {
        //no op
    }

    public void remove(WebContext pCtx, Object obj) {
        //readonly for now
    }

    public void removeListDataListener(ListDataListener l) {
        //no op
    }

    public void updateView(WebContext pCtx) {
        evaluate(pCtx);
    }

    protected void evaluate(FacesContext ctx) {
        super.evaluate(ctx);
        populate((WebContext) ctx);
    }

    void add(Object obj) {
        if (obj == null) {
            return;
        }

        list.add(obj);
    }

    private void populate(WebContext ctx) {
        try {
            if (ctx.isRenderResponse) {
                return;
            }

            list.clear();

            if (category == null) {
                return;
            }

            CatalogManager.initialize(ctx.getWebTop() + "WEB-INF" + File.separator + "searchConfig.xml");

            String catName = (String)AttributeEvaluator.evaluate(ctx, this, category);

            Catalog cat = CatalogManager.getCatalog(catName);
            cat.setPageSize(pageSize);

            String location = com.jb.web.application.configuration.Config.getInstance().getSearchIndexLocation() +
                File.separator + "search" + File.separator + cat.getName();

            if (!(new File(location).exists())) {
                ctx.addErrorMessage(this, "Index file not found " + location);
                ctx.renderResponse();

                return;
            }

            cat.setIndexLocation(location);

            String query = (String)AttributeEvaluator.evaluate(ctx, this, getValue());

            //     MyRenderer renderer = new MyRenderer(this);
            StringWriter writer = new StringWriter();
            SearchHits hits = new CatalogSearch(cat, writer).search(query, pageNo);
            
            
            /*int len= hits.getHits();
            for(int i=0;i<hits.getHits();i++)
            {
              list.add(hits.getDocument(i));
            }*/
            result = writer.getBuffer();

            //   System.err.println(result);
        } catch (Throwable t) {
        }
    }
}


class MyRenderer extends HitsRenderer {
    SearchList list;

    MyRenderer(SearchList list) {
        this.list = list;
    }

    public void renderBegin(HitMateData md) throws RenderException {
    }

    public void renderDocument(HitMateData md, SourceDocument pDocument)
        throws RenderException {
        list.add(documentToObject(pDocument));
    }

    public void renderEnd(HitMateData md) throws RenderException {
    }

    private Object documentToObject(SourceDocument pDocument) {
        String beanClass = list.getBeanClass();

        if ((beanClass != null) && (beanClass.length() != 0)) {
            Object mb = ClassUtil.createInstance(beanClass);
            if(mb!=null)
                updateWithDocument(mb, pDocument);
            return mb;
        } else {
            return pDocument;
        }
    }

    private void updateWithDocument(Object root, SourceDocument pDocument) {
        try {
            HashMap hm = PropUtil.getPropertyDescriptorsMap(root.getClass());
            Iterator it = hm.keySet().iterator();

            while (it.hasNext()) {
                String pName = (String) it.next();
                PropertyDescriptor pd = (PropertyDescriptor) hm.get(pName);

                try {
                    Object pValue = null;
                    Object searchValue = pDocument.getFieldValue(pName);

                    if (searchValue == null) {
                        continue;
                    }

                    if (pd.getPropertyType() == String.class) {
                        pValue = searchValue;
                    }
                   
                    if ((pd.getPropertyType() == long.class) || (pd.getPropertyType() == Long.class)) {
                        pValue = new Long("" + searchValue);
                    }

                    if ((pd.getPropertyType() == int.class) || (pd.getPropertyType() == Integer.class)) {
                        pValue = new Integer(pDocument.getFieldValue(pName));
                    }

                    if ((pd.getPropertyType() == float.class) || (pd.getPropertyType() == Float.class)) {
                        pValue = new Float("" + searchValue);
                    }

                    if ((pd.getPropertyType() == double.class) || (pd.getPropertyType() == Double.class)) {
                        pValue = new Double("" + searchValue);
                    }

                    if ((pd.getPropertyType() == boolean.class) || (pd.getPropertyType() == Boolean.class)) {
                        pValue = new Boolean("" + searchValue);
                    }

                    if (pValue != null) {
                        PropUtil.setProperty(root, pName, pValue);
                    }
                } catch (Exception e) {
                    
                    //   System.out.println(pName + " does not exist in database "+root.getClass().getName());
                }
            }
        } catch (Exception e) {
        }
    }
}
